#include <iostream>
#include <cstdio>
#include <fstream>
#include "feature.h"
#include "tagger.h"
#include "CRFTagger.h"
//collect all the features
namespace MRFPP
{
const int INF_ID = 1000000;
bool FeatureIndex::open(const char* filename,bool isCRF)
{
	std::ifstream in(filename);
	if(!in)
		return false;
	std::string line;
	std::string token;
	std::vector <std::string> tokenlist;
	int n = 0;
	while(std::getline(in,line))
	{
		token = "";
		tokenlist.clear();
		for(size_t i = 0; i < line.size(); i++)
		{
			if(line[i] == ' ' && token == "")
				continue;
			else if(line[i] == ' ')
			{
				tokenlist.push_back(token);
				token = "";
			}
			else
				token += line[i];
		}
		tokenlist.push_back(token);
		data_.push_back(tokenlist);
		length.push_back(tokenlist.size());
		if (isCRF)
		{
			std::string tag;
			getline(in,line);
			std::vector <int> answer;
			for(size_t i = 0; i < line.size(); i++)
			{
				if(line[i] == '/')
				{
					answer.push_back(getTagID(tag));
					tag.clear();
				}
				else
					tag += line[i];
			}
			answer.push_back(getTagID(tag));
			answers_.push_back(answer);
		}
		n++;
	}
	in.close();
	return true;
}
void FeatureIndex::getFeatures(Tagger* x, std::vector <std::string> & data_, std::vector<int>& answer_)
{
		x->set_feature_id(feature_cache_.size());
		extractWordFeature(data_[0]);
		for(size_t j = 1; j < data_.size(); j++)
		{
			extractWordFeature(data_[j]);
			extractEdgeFeature();
		}
			x -> setTag(answer_);
}

bool FeatureIndex::openFeatures(bool isCRF, std::vector <Tagger*>& x)
{
	for(size_t i = 0; i < data_.size(); i++)
	{
		x.push_back(new CRFTagger(alpha_));
		getFeatures(x[i],data_[i],answers_[i]);
	}
	std::cout << "map the features..." << std::endl;
	std::cout << "total feature num is " << size() << std::endl;
	std::cout << "total tags is.." << y_.size() << std::endl;
}

int FeatureIndex::getTagID(std::string key)
{
	std::map <std::string, int >::iterator it = tagdic_.find(key);
	if (it == tagdic_.end())
	{
		tagdic_.insert(std::make_pair<std::string ,int > (key,maxtagid_));
		y_.push_back(key);
		tag_.push_back(key);
		return maxtagid_++;
	}
	else
	{
		return it -> second;
	}
}
//to find the tag id for decoder 
int FeatureIndex::TagID(std::string key)
{	
	std::map <std::string, int >::iterator it = tagdic_.find(key);
	if (it == tagdic_.end())
	{
		return INF_ID;
	}
	else
	{
		return it -> second;
	}


}

int FeatureIndex::addFeature(std::string key, bool isEdge)
{
	std::map <std::string, std::pair<int, int> >::iterator it = dic_.find(key);
	if (it == dic_.end())
	{
		dic_.insert(std::make_pair<std::string ,std::pair<int, int> > (key,std::make_pair<int, int>(maxid_,1)));
		int cur = maxid_;
		maxid_ += isEdge ? y_.size() * y_.size() : y_.size();
		return cur;
	}
	else
	{
		it -> second.second++;
		return it -> second.first;
	}
}

void FeatureIndex::extractWordFeature(std::string word)
{
	//word
	std::vector <int> feature;

	feature.push_back(addFeature(("word=" + word), false));
	//suffix-2
	if (useSuffixFeatures)
	{
		for (int s = 1; s <= suffixLength && word.size() > s; s++)
		{
			std::string suffix = word.substr(word.size() - s);
			char buffer[10];
			sprintf(buffer,"%d",s);
			feature.push_back(addFeature(std::string("suffix-") + buffer + std::string("=") + suffix, false));
		}
	}

	if (useHasHyphen)
	{
		if (word.find("-"))
		{
			feature.push_back(addFeature("hasHypen", false));
		}
	}
	//protype

	feature_cache_.push_back(feature);

}

void FeatureIndex::extractEdgeFeature( )//std::string before,std::string cur)
{
	std::vector <int> feature;
	feature.push_back(addFeature("edge=B",true));
	feature_cache_.push_back(feature);
}
void FeatureIndex::update(Tagger* tagger)
{
	size_t fid = tagger -> feature_id();
	for(size_t cur = 0; cur < tagger ->size();++cur)
	{
		std::vector<int> f = feature_cache_[fid++];
			tagger -> updateNodePotential(cur,f);
		if (cur > 0)
		{
			std::vector <int> f = feature_cache_[fid++];
			for(size_t i = 0; i < y_.size(); i++)
					tagger -> updateEdgePotential(i,cur,f);
		}
		
	}
}

void FeatureIndex::buildFeatures(Tagger* tagger)
{
	
	size_t fid = tagger->feature_id();
	for(size_t cur = 0; cur < tagger->size();++cur)
	{
		
		std::vector <int> f = feature_cache_[fid++];
		for(size_t i = 0; i < y_.size(); i++)
		{
			tagger->fillNodePotential(cur,i,f);	
		}
		
		if (cur > 0)
		{
			std::vector <int> f = feature_cache_[fid++];
			for(size_t i = 0; i < y_.size(); i++)
				for(size_t j = 0; j < y_.size(); j++)
				{
					tagger -> fillEdgePotential(i,j,cur,f);
				}
		}
		
	}
}
}
